# -*- coding: utf-8 -*-
# @Time    : 2024/11/21 
# @Author  : bcbai
# @File    : uds.py
# @Software: vscode
# @Description: 用户点击界面后，后端处理流程


import json
# from ctypes import *
# import time
import re

from libTSCANAPI import *
from PyQt5.QtCore import QThread, pyqtSignal

# from myLog import logger
from seedtokey import seedToKey_L5
from parseFlashFile import parse_s19_file, parse_hex_file
from udsFunctions import *             # 导入自己封装好的诊断相关函数

'''
子线程只只负责执行tscan相关操作, 不负责UI界面的显示
'''








can_msg_0x505 = TLIBCAN(
    FIdxChn = 0,
    FDLC = 8,
    FIdentifier = 0x505,  # WPC053 理想PWLC
    FProperties = 1,
    FData = [00, 00, 00, 00, 00, 00, 0x20, 00]
)

can_msg_0x2C3_enable = TLIBCAN(
    FIdxChn = 0,
    FDLC = 8,
    FIdentifier = 0x2C3,  # WPC053
    FProperties = 1,
    FData = [10, 00, 00, 00, 00, 00, 00, 00]
)

can_msg_0x2C3_disable = TLIBCAN(
    FIdxChn = 0,
    FDLC = 8,
    FIdentifier = 0x2C3,  # WPC053
    FProperties = 1,
    FData = [00, 00, 00, 00, 00, 00, 00, 00]
)

can_msg_0x2BA_enable = TLIBCAN( # 0x2BA 打开电源模式
    FIdxChn = 0,
    FDLC = 8,
    FIdentifier = 0x2BA,
    FProperties = 1,
    FData = [0x40, 00, 00, 00, 00, 00, 00, 00]
)

can_msg_0x2BA_disable = TLIBCAN( # 0x2BA 关闭电源模式
    FIdxChn = 0,
    FDLC = 8,
    FIdentifier = 0x2BA,
    FProperties = 1,
    FData = [00, 00, 00, 00, 00, 00, 00, 00]
)


class WorkThread(QThread):
    # 定义子线程信号, 用于接收ui主线程的命令信号
    work_signal_baseUdsread = pyqtSignal(str)
    work_signal_connect = pyqtSignal(str)
    work_signal_disconnect = pyqtSignal(str)
    work_signal_chargeOnOff = pyqtSignal(str)
    work_signal_reset_ECU = pyqtSignal(str)
    work_signal_read = pyqtSignal(str)
    work_signal_write_ECU_manufacture_date = pyqtSignal(str) # 写ECU制造日期 的信号
    work_signal_write_ASC_number = pyqtSignal(str)           # 写硬件PN、SN序列号、ECU序列号... 的信号
    work_signal_write_HW_part_number = pyqtSignal(str)       # 写硬件PN 的信号
    work_signal_write_fast_charge_key = pyqtSignal(str)      # 写手机快充key 的信号
    work_signal_write_fan_speed = pyqtSignal(str)            # 写风扇速度 的信号
    work_signal_QValue_Adjust = pyqtSignal(str)              # Q值校准 的信号
    work_signal_fastChargeSwitchVerify = pyqtSignal(str)     # 快速充电验证 的信号
    work_signal_flash = pyqtSignal(str)                      # 刷写信号


    def __init__(self, HWHandle, signal_list):
        super().__init__()


        self.is_cycle = False
        self.cycle_time = 0
        self.flash_flag = False  # 初始化flash标志位为false
        self.driver_data = "" 
        self.app_data = ""       # 存放读取到的hex数据
        

        self.HWHandle = HWHandle
        self.ECU_type = "null"
        # 获取ui主线程的信号对象，用于发送执行结果
        self.ui_signal_connect_result = signal_list[0]
        self.ui_signal_showReadBaseInfo = signal_list[1]
        self.ui_signal_showWriteResult = signal_list[2]
        self.ui_signal_showUiResult = signal_list[3]



    def run(self):
        while True:
            time.sleep(0.5)
            if self.flash_flag:
                self.flash_flag = False
                self.flash()
            if self.is_cycle and self.is_cycle > 0 and self.flash_flag == False:
                self.readBaseInfo()
                time.sleep(self.cycle_time)


    # 连接同星
    def connect(self, str):
        str = json.loads(str)
        self.ECU_type = str["ECU_type"]
        logger.info("ECU_type: {}".format(self.ECU_type))
        # initialize_lib_tscan(True, True, False)
        # self.HWHandle = c_size_t(0)
        ret = tsapp_connect(b"", self.HWHandle)
        if ret != 0:
            logger.error("同星连接失败, error code: {}".format(ret))
            str = json.dumps({"res":"connect fail", "msg":"失败，是不是没接同星？错误码: {}".format(ret)})
        else:
            logger.info("同星连接成功")
            # 配置波特率等
            tsapp_configure_baudrate_canfd(self.HWHandle, 0, 500, 2000, 1, 0, 1)
            # tsapp_register_event_can_whandle()
            # 创建诊断模块
            if self.createDiagModule() == 0:
                logger.info("诊断模块创建成功")
                # tsdiag_can_attach_to_tscan_tool
            else:
                logger.error("诊断模块创建失败")

            ACount =c_int32(0)
            tscan_scan_devices(ACount) # 扫描设备才能得到序列号等信息
            logger.info("在线设备数量 = {}".format(ACount.value))
            for i in range(ACount.value):
                AFManufacturer = c_char_p() #厂商
                AFProduct = c_char_p()      # 产品
                AFSerial = c_char_p()       #序列号
                tscan_get_device_info(i, AFManufacturer, AFProduct, AFSerial)
                logger.info("序列号 ={}".format(AFSerial.value.decode()))
            str = json.dumps({"res":"connect success","msg":"连接成功 :" + AFSerial.value.decode()})
        self.ui_signal_connect_result.emit(str)


    # 创建诊断模块
    def createDiagModule(self):
        if self.ECU_type == "WPC053":
            reqID = c_int32(0x650)              # 请求ID
            resID = c_int32(0x6D0)              # 应答ID
            AFctID = c_int32(0x601)             # 功能ID
        elif self.ECU_type == "WPC053_1":
            reqID = c_int32(0x638)              
            resID = c_int32(0x6B8)
            AFctID = c_int32(0x601)             

        self.udsHandle = c_uint8(0)         # 诊断模块句柄
        ChnIndex = CHANNEL_INDEX.CHN1       # 通道号
        ASupportFD = False                  # 是否支持CANFD
        AMaxdlc = 8                         # 最大帧长度
        ARequestIDIsStd = True              # 请求ID是否标准帧
        resIsStd = True                     # 应答ID是否标准帧
        fctIsStd = True                     # 功能ID是否标准帧

        ret = tsdiag_can_create(self.HWHandle,
                                self.udsHandle,
                                ChnIndex, 
                                ASupportFD, 
                                AMaxdlc, 
                                reqID, 
                                ARequestIDIsStd, 
                                resID, 
                                resIsStd, 
                                AFctID, 
                                fctIsStd)
        logger.info("tsdiag_can_create 结果: {}".format(ret))
        tsdiag_can_create

        # 同星连接后发基础报文唤醒
        self.__SendMsg(can_msg_0x505, is_cyclic=True, Atimeout = 100)
        self.__SendMsg(can_msg_0x2C3_disable, is_cyclic=True, Atimeout = 20)
        self.__SendMsg(can_msg_0x2BA_disable, is_cyclic=True, Atimeout = 100)
        return ret


    # 断开同星连接
    def disconnect(self):
        ret1 = tsdiag_can_delete(self.udsHandle)  # 先销毁诊断模块
        if ret1 != 0:
            logger.error("销毁诊断模块失败, error code: {ret}")
        else:
            logger.info("销毁诊断模块成功")

        ret2 = tsapp_disconnect_by_handle(self.HWHandle)
        if ret2 != 0:
            logger.error("断开失败, error code: {ret}")
            str = json.dumps({"res":"disconnect fail", "msg":"断开失败,同星SDK错误码: {}".format(ret2)})
        else:
            logger.info("已断开连接")
            str = json.dumps({"res":"disconnect success", "msg":"已断开连接"})
        self.ui_signal_connect_result.emit(str)


    # 开/关充电
    def chargeOnOff(self, str):
        str = json.loads(str)
        cmd = str["cmd"]
        if cmd == "chargeON":
            # 周期发送报文，打开充电
            self.__SendMsg(can_msg_0x505, is_cyclic=True, Atimeout = 100)
            self.__SendMsg(can_msg_0x2C3_enable, is_cyclic=True, Atimeout = 20)
            self.__SendMsg(can_msg_0x2BA_enable, is_cyclic=True, Atimeout = 100)
        else:
            # 周期发送报文，关闭充电
            self.__SendMsg(can_msg_0x505, is_cyclic=True, Atimeout = 100)
            self.__SendMsg(can_msg_0x2C3_disable, is_cyclic=True, Atimeout = 20)
            self.__SendMsg(can_msg_0x2BA_disable, is_cyclic=True, Atimeout = 100)


    # 发送报文
    def __SendMsg(self, msg, is_cyclic=False, is_asnyc=True, is_send=True, Atimeout = 0):
            if Atimeout != 0:
                timeout = Atimeout
            else:
                timeout = 100
                ATimeout = self.tb_CycliTime.text().strip()
                if ATimeout.isdigit():
                    timeout = int(ATimeout,16)
            if isinstance(msg,TLIBCANFD):
                if not is_send:
                    return tsapp_delete_cyclic_msg_canfd(self.HWHandle,msg)
                if is_cyclic:
                    return tsapp_add_cyclic_msg_canfd(self.HWHandle,msg,timeout)
                if is_asnyc:
                    return tsapp_transmit_canfd_async(self.HWHandle,msg)
                else:
                    return tsapp_transmit_canfd_sync(self.HWHandle,msg,timeout)
            elif isinstance(msg,TLIBCAN):
                if not is_send:
                    return tsapp_delete_cyclic_msg_can(self.HWHandle,msg)
                if is_cyclic:
                    logger.info("周期发送can报文")
                    return tsapp_add_cyclic_msg_can(self.HWHandle,msg,timeout)
                if is_asnyc:
                    return tsapp_transmit_can_async(self.HWHandle,msg)
                else:
                    return tsapp_transmit_can_sync(self.HWHandle,msg,timeout)
            elif isinstance(msg,TLIBLIN):
                # if not is_send:
                #     return tsapp_delete_cyclic_msg_canfd(self.HWHandle,msg)
                if is_asnyc:
                    return tsapp_transmit_lin_async(self.HWHandle,msg)
                else:
                    return tsapp_transmit_lin_sync(self.HWHandle,msg,timeout)
            elif isinstance(msg,TLIBFlexray):
                # if not is_send:
                #     return tsapp_delete_cyclic_msg_canfd(self.HWHandle,msg)
                if is_asnyc:
                    return tsapp_transmit_flexray_async(self.HWHandle,msg)
                else:
                    return tsapp_transmit_flexray_sync(self.HWHandle,msg,timeout)
            else:
                return -1


    def resetECU(self):
        r = ECU_Reset(self.udsHandle, reset_time = 3)
        if r != 0:
            result = json.dumps({'result_type' : 'msgBox', 'msg' : "ECU复位失败"})
            self.ui_signal_showUiResult.emit(result)
        else:
            result = json.dumps({'result_type' : 'msgBox', 'msg' : "ECU复位成功"})
            self.ui_signal_showUiResult.emit(result)



    def handleReadBaseInfo(self, str):
        str = json.loads(str)
        is_cycle = str["is_cycle"]
        cycle_time = int(str["cycle_time"])
        if is_cycle == True:
            self.cycle_time = cycle_time
            self.is_cycle = True  # 此时，在run()函数中执行耗时操作
        else:
            self.is_cycle = False 
            self.readBaseInfo()


    def readBaseInfo(self):
        # 响应数据的类型是Hex Array 或 ASCii
        response_value_type_Hex = 'Hex'
        response_value_type_ASC = 'ASCii'  # 这里默认是Intel格式
        response_value_type_Int8 = 'Int8'
        response_value_type_Int16 = 'Int16'

        # -------10 01 或 10 03下直接读取：----------
        # 读立讯小版本号 22 10 01
        request_read_lux_version =  (c_uint8*3)(0x22,0x10, 0x01)
        str_lux_version = uds22Service_response(self.udsHandle, request_read_lux_version, response_value_type_ASC)
        logger.info("lux_version: {}".format(str_lux_version))

        # 读ECU软件版本号 22 F1 95
        request_read_SW_version =  (c_uint8*3)(0x22,0xF1, 0x95)  # 数组类型的请求报文
        str_SW_version = uds22Service_response(self.udsHandle, request_read_SW_version, response_value_type_Hex)
        logger.info("SW_version: {}".format(str_SW_version))

        # 读ECU硬件版本号 22 F1 93
        request_read_HW_version =  (c_uint8*3)(0x22,0xF1, 0x93)
        str_HW_version = uds22Service_response(self.udsHandle, request_read_HW_version, response_value_type_Hex)
        logger.info("HW_version: {}".format(str_HW_version))

        # 读BT版本号(bootloader) 22 F1 50
        request_read_BT_version =  (c_uint8*3)(0x22,0xF1, 0x50)
        str_BT_version = uds22Service_response(self.udsHandle, request_read_BT_version, response_value_type_Hex)
        logger.info("BT_version: {}".format(str_BT_version))

        # 读硬件零件号PN 22 F1 10
        request_read_HW_part_number =  (c_uint8*3)(0x22,0xF1, 0x10)
        str_HW_part_number = uds22Service_response(self.udsHandle, request_read_HW_part_number, response_value_type_ASC)
        logger.info("HW_part_number: {}".format(str_HW_part_number))

        # 读软件零件号PN 22 F1 18
        request_read_SW_part_number =  (c_uint8*3)(0x22,0xF1, 0x18)
        str_SW_part_number = uds22Service_response(self.udsHandle, request_read_SW_part_number, response_value_type_ASC)
        logger.info("SW_part_number: {}".format(str_SW_part_number))

        # 读SN序列号 22 F1 8C
        request_read_SN =  (c_uint8*3)(0x22,0xF1, 0x8C)
        str_SN = uds22Service_response(self.udsHandle, request_read_SN, response_value_type_ASC)
        logger.info("SN: {}".format(str_SN))

        # 读供应商ID 22 F1 8A
        request_read_supplier_ID =  (c_uint8*3)(0x22,0xF1, 0x8A)
        str_supplier_ID = uds22Service_response(self.udsHandle, request_read_supplier_ID, response_value_type_ASC)
        logger.info("supplier_ID: {}".format(str_supplier_ID))

        # 读ECU名称 22 F1 97
        request_read_ECU_name =  (c_uint8*3)(0x22,0xF1, 0x97)
        str_ECU_name = uds22Service_response(self.udsHandle, request_read_ECU_name, response_value_type_ASC)
        logger.info("ECU_name: {}".format(str_ECU_name))

        # 读NTC温度 22 FD 0A
        request_read_NTC_temperature =  (c_uint8*3)(0x22,0xFD, 0x0A)
        str_NTC_temperature = uds22Service_response(self.udsHandle, request_read_NTC_temperature, response_value_type_Int16)
        logger.info("NTC_temperature: {}".format(str_NTC_temperature))

        # 读线圈Q值 22 41 2D
        request_read_coil_Q_value =  (c_uint8*3)(0x22,0x41, 0x2D)
        str_coil_Q_value = uds22Service_response(self.udsHandle, request_read_coil_Q_value, response_value_type_Int16)
        logger.info("coil_Q_value: {}".format(str_coil_Q_value))

        # 读ECU制造日期 22 F1 8B
        request_read_ECU_manufacture_date =  (c_uint8*3)(0x22,0xF1, 0x8B)
        str_ECU_manufacture_date = uds22Service_response(self.udsHandle, request_read_ECU_manufacture_date, response_value_type_Int8)
        logger.info("ECU_manufacture_date: {}".format(str_ECU_manufacture_date))

        # 读ECU流水号 22 F1 8C
        request_read_ECU_serial_number =  (c_uint8*3)(0x22,0xF1, 0x8C)
        str_ECU_serial_number = uds22Service_response(self.udsHandle, request_read_ECU_serial_number, response_value_type_ASC)
        logger.info("ECU_serial_number: {}".format(str_ECU_serial_number))

        # 读风扇转速 22 FD 04
        request_read_fan_speed =  (c_uint8*3)(0x22, 0xFD, 0x04)
        str_fan_speed = uds22Service_response(self.udsHandle, request_read_fan_speed, response_value_type_Hex)
        logger.info("fan_speed: {}".format(str_fan_speed))

        # ------- 读取以下数值，需要先过安全访问 ↓↓↓ ----------

        # 进入 10 03 扩展会话
        r = tsdiag_can_session_control(self.udsHandle, 0x03)  
        if r!= 0:
            res= c_char_p()
            tscan_get_error_description(r, res)
            logger.error("tsdiag_can_session_control error_Code:{}, desc:{}".format(r, res.value))
        logger.info("进入 10 03 扩展会话成功")

        # 安全访问
        security_level = 0x61
        security_access_result = uds27Service_response(self.udsHandle, security_level) 
        if  security_access_result != 0: 
            str_coil_QLC = "安全访问失败"
            str_xiaomi_key = "安全访问失败"
            str_OPPO_key = "安全访问失败"
            str_private_key_status_and_fast_charging_switch = '安全访问失败'
        else: 
            # 读线圈QLC  22 41 2A
            request_read_coil_QLC =  (c_uint8*3)(0x22, 0x41, 0x2A)
            str_coil_QLC = uds22Service_response(self.udsHandle, request_read_coil_QLC, response_value_type_Hex)
            logger.info("coil_QLC: {}".format(str_coil_QLC))

            # 读xiaomi key  22 FD 02
            request_read_xiaomi_key =  (c_uint8*3)(0x22, 0xFD, 0x02)
            str_xiaomi_key = uds22Service_response(self.udsHandle, request_read_xiaomi_key, response_value_type_Hex)
            logger.info("xiaomi_key: {}".format(str_xiaomi_key))

            # 读OPPO key  22 FD 0B
            request_read_oppo_key =  (c_uint8*3)(0x22, 0xFD, 0x0B)
            str_OPPO_key = uds22Service_response(self.udsHandle, request_read_oppo_key, response_value_type_Hex)
            logger.info("OPPO_key: {}".format(str_OPPO_key))

            # 读私有密钥状态及快充开关 22 42 09
            request_read_private_key_status_and_fast_charging_switch =  (c_uint8*3)(0x22, 0x42, 0x09)
            str_private_key_status_and_fast_charging_switch = uds22Service_response(self.udsHandle, request_read_private_key_status_and_fast_charging_switch, response_value_type_Hex)
            logger.info("private_key_status: {}".format(type(str_private_key_status_and_fast_charging_switch)))


        # 把读取到的基础诊断信息，发送到UI界面
        str = json.dumps({
                        "SW_version":str_SW_version,
                        "HW_version":str_HW_version,
                        "BT_version":str_BT_version,
                        "lux_version":str_lux_version,
                        "HW_part_number":str_HW_part_number,
                        "SW_part_number":str_SW_part_number,
                        "SN":str_SN,
                        "supplier_ID":str_supplier_ID,
                        "ECU_name":str_ECU_name,
                        "NTC_temperature":str_NTC_temperature,
                        "coil_Q_value":str_coil_Q_value,
                        "ECU_manufacture_date":str_ECU_manufacture_date,
                        "ECU_serial_number":str_ECU_serial_number,
                        "fan_speed":str_fan_speed,
                        "coil_QLC":str_coil_QLC,
                        "xiaomi_key":str_xiaomi_key,
                        "OPPO_key":str_OPPO_key,
                        "private_key_status_and_fast_charging_switch":str_private_key_status_and_fast_charging_switch
                        })
        self.ui_signal_showReadBaseInfo.emit(str)



    # 写ECU制造日期
    def writeECUManufactureDate(self, str):
        str = json.loads(str)
        year = int(str["year"])
        month = int(str["month"])
        day = int(str["day"])
        # logger.info("year, month, day :{} {} {}".format(year, month, day))
        request_write_ECU_manufacture_date = (c_uint8*6)(0x2E, 0xFD, 0x07, year, month, day)
        write_result = uds2EService_response(self.udsHandle, request_write_ECU_manufacture_date)
        str = json.dumps({'write_result' : '写生产日期' + write_result})
        self.ui_signal_showWriteResult.emit(str)


    # def writeECUSerialNumber(self, str):
    def writeASCNumber(self, str):
        str = json.loads(str)
        ASC_type = str["ASC_type"]
        str_input = str["str_input"]
        if str_input == '':
            write_result = '失败 不能为空 !'
        else:
            # 写ECU流水号 2E F1 8C
            if ASC_type == "SN":
                str_SN = str_input.strip()
                list_str = list(str_SN)
                if len(list_str) > 13:
                    list_str = list_str[:13]  # 如果用户输入长度超过13字节，舍弃多余的
                int_SN_values = [ord(char) for char in list_str]  # asc 转 int
                request_list = [0x2E,0xFD, 0x08] + int_SN_values
                request_write_ECU_serial_number = (c_uint8*16)(*request_list) # 13+3=16
                write_result = uds2EService_response(self.udsHandle, request_write_ECU_serial_number)
            # 写硬件PN码 2E FD 05
            elif ASC_type == "HW_part_number":
                str_HW_part_number = str_input.strip()
                list_str = list(str_HW_part_number)
                if len(list_str) > 11:
                    list_str = list_str[:11]  # 如果用户输入长度超过11字节，舍弃多余的
                int__values = [ord(char) for char in list_str]  # asc 转 int
                request_list = [0x2E,0xFD, 0x05] + int__values
                request_write_ECU_serial_number = (c_uint8*14)(*request_list)  # 11+3=14
                write_result = uds2EService_response(self.udsHandle, request_write_ECU_serial_number)

            str = json.dumps({'write_result' : '写流水编号' + write_result})
            self.ui_signal_showWriteResult.emit(str)


    # 写快充key
    def writeFastChargeKey(self, str):
        str = json.loads(str)
        str_key = str["str_fast_charge_key"].strip()
        phone = str["phone"]
        if len(str_key) == 0: 
            write_result = '失败: 长度不对 !'
        if bool(re.match("^[a-fA-F0-9 ]*$", str_key)) == False: # 校验是否只有数字、字母(A~F)、空格
            write_result = '失败: 格式不对 !'
        else:
            str_key = re.sub(r'\s', '', str_key) # 去掉所有空格
            str_list_xiaomi_key = [str_key[i:i+2] for i in range(0, len(str_key), 2)]
            int_list_key = [int(item, 16) for item in str_list_xiaomi_key] # 字符串转int类型
            logger.info('list_key: {}'.format(int_list_key))

            if phone == 'xiaomi': 
                if len(int_list_key) != 8:
                    write_result = '失败: 长度不对 !'  
                else:
                    request_list = [0x2E,0xFD, 0x02] + int_list_key
                    request_write_fast_charge = (c_uint8*len(request_list))(*request_list)
                    write_result = uds2EService_response(self.udsHandle, request_write_fast_charge)

            elif phone == 'OPPO':
                if len(int_list_key)!= 16:
                    write_result = '失败: 长度不对!'
                else:
                    request_list = [0x2E,0xFD, 0x0B] + int_list_key
                    request_write_fast_charge = (c_uint8*len(request_list))(*request_list)
                    write_result = uds2EService_response(self.udsHandle, request_write_fast_charge)

        str = json.dumps({'write_result' : '写' + phone + 'key' + write_result})
        self.ui_signal_showWriteResult.emit(str)

    
    # 写风扇转速
    def writeFanSpeed(self, str):
        str = json.loads(str)
        str_fan_speed = str["str_fan_speed"].strip()
        if str_fan_speed =='stop':
            request_list = [0x2E, 0xFD, 0x04, 0x00, 0, 0, 0] # 0x00 表示停止风扇
            logger.info('writeFanSpeed / request_list: {}'.format(request_list))
            request_write_fan_speed = (c_uint8*7)(*request_list)
            write_result = uds2EService_response(self.udsHandle, request_write_fan_speed)
            
        elif (len(str_fan_speed) == 0) or\
            (bool(re.match("^[0-9 ]*$", str_fan_speed)) == False) or \
            (int(str_fan_speed) > 100) or \
            (int(str_fan_speed) < 0): 
            write_result = '失败: 格式不对 !'

        else:
            str_fan_speed = re.sub(r'\s', '', str_fan_speed) # 去掉所有空格
            int_fan_speed = int(str_fan_speed)
            request_list = [0x2E, 0xFD, 0x04, 0x01, int_fan_speed, 0, 0]
            logger.info('writeFanSpeed / request_list: {}'.format(request_list))
            request_write_fan_speed = (c_uint8*7)(*request_list)
            write_result = uds2EService_response(self.udsHandle, request_write_fan_speed)

        str = json.dumps({'write_result' : '写风扇转速' + write_result})
        self.ui_signal_showWriteResult.emit(str)


    # Q值校准
    def QValueAdjust(self):
        if self.ECU_type == "WPC053":
            request_list = [0x31, 0x01, 0x41, 0x10]
        elif self.ECU_type == "WPC053_1":
            request_list = [0x31, 0x01, 0x41, 0x10]

        adjust_result = ''
        # 进10 03扩展会话
        r = tsdiag_can_session_control(self.udsHandle, 0x03)
        if r!= 0:
            res= c_char_p()
            tscan_get_error_description(r, res)
            logger.error("tsdiag_can_session_control error_Code:{}, desc:{}".format(r, res.value))
            adjust_result = '进扩展会话失败'
        else:
            # 安全访问
            security_level = 0x61
            security_access_result = uds27Service_response(self.udsHandle, security_level) 
            if  security_access_result != 0: 
                adjust_result = "安全访问失败"
            else:
                request_data = (c_uint8*4)(*request_list)
                response_data_size = c_int(100)  # 写100或1000都行
                response_data = (c_uint8 * 100)()
                r = tstp_can_request_and_get_response(self.udsHandle, request_data, len(request_data), response_data, response_data_size)
                if r!= 0:
                    res= c_char_p()
                    tscan_get_error_description(r, res)
                    logger.error("uds2EService_response error_Code:{}, desc:{}".format(r, res.value))
                    adjust_result = '校准命令发送失败'
                else:
                    list_result = []
                    for i in range(response_data_size.value):
                        list_result.append(hex(response_data[i]))

                    logger.info('QValueAdjust / list_result: {}'.format(list_result))
                    if list_result[0] == '0x71' and  list_result[4] == '0x0':
                        adjust_result = '校准成功,请5秒后,下电再上电 '
                    else:
                        str_result = " ".join([item[2:].zfill(2).upper() for item in list_result])
                        adjust_result = '校准失败' + str_result

        result = json.dumps({'result_type' : 'msgBox', 'msg' : adjust_result})
        self.ui_signal_showUiResult.emit(result)


    # 快充开关确认 2E 42 09 
    def fastChargeSwitchVerify(self, str):
        str = json.loads(str)
        switch_xiaomi = str["switch_xiaomi"]
        switch_OPPO = str["switch_OPPO"]
        switch_VIVO = str["switch_VIVO"]
        switch_HUAWEI = str["switch_HUAWEI"]
        switch_Honor = str["switch_Honor"]
        byte0_xiaomi = 0x10 if switch_xiaomi == 1 else 0x00
        byte1_OPPO = 0x10 if switch_OPPO == 1 else 0x00
        byte2_VIVO = 0x10 if switch_VIVO == 1 else 0x00
        byte3_HUAWEI = 0x10 if switch_HUAWEI == 1 else 0x00
        byte4_Honor = 0x10 if switch_Honor == 1 else 0x00

        switch_list = [byte0_xiaomi, byte1_OPPO, byte2_VIVO, byte3_HUAWEI, byte4_Honor, 0x00, 0x00, 0x00, 0x00, 0x00]
        request_list = [0x2E, 0x42, 0x09] + switch_list
        request_data = (c_uint8*len(request_list))(*request_list)
        try:
            write_result = uds2EService_response(self.udsHandle, request_data)
        except:
            write_result = '失败'
        str = json.dumps({'write_result' : '写快充开关' + write_result})
        self.ui_signal_showWriteResult.emit(str)


    def handleFlash(self, str):
        str = json.loads(str)
        app_file_path = str["app_file_path"].strip()
        driver_file_path = str["driver_file_path"].strip()

        self.driver_data = parse_hex_file(driver_file_path)  # 解析driver文件数据
        self.app_data = parse_s19_file(app_file_path)              # 解析app文件数据

        if self.driver_data["data_length"] == 0:
            result = json.dumps({'result_type' : 'msgBox', 'msg' : "解析driver文件失败"})
            self.ui_signal_showUiResult.emit(result)
            return
        elif self.app_data["start_address"] == 0:
            result = json.dumps({'result_type' : 'msgBox', 'msg' : "解析app文件失败"})
            self.ui_signal_showUiResult.emit(result)
            return
        else:
            logger.info("开始刷写...")
            self.flash_flag = True


    def flash(self):
        res= c_char_p()

        driver_data = self.driver_data["parsed_data"]             # 数据
        driver_data_length = self.driver_data["data_length"]      # 数据长度
        driver_start_address = self.driver_data["start_address"]  # 刷写地址

        app_data = self.app_data["parsed_data"]             
        app_data_length = self.app_data["data_length"]      
        app_start_address = self.app_data["start_address"]  

        step_describle = "10 03进扩展会话"
        progress_value = 5
        r = tsdiag_can_session_control(self.udsHandle, 0x03)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return
            

        step_describle = "31 01 02 03检查预编程条件"
        progress_value = 10
        request_data = (c_uint8*4)(0x31, 0x01, 0x02, 0x03)
        r = uds31Service_response(self.udsHandle, request_data, type_preProgramConditionCheck)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return

        step_describle = "85 02关闭DTC记录"
        progress_value = 15
        r = closeDTCRecord(self.udsHandle)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return


        step_describle = "28 01 03关闭常规报文收发"
        progress_value = 20
        r = disableNMAndAppMessage(self.udsHandle)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return


        step_describle = "10 02进编程会话"
        progress_value = 25
        r = tsdiag_can_session_control(self.udsHandle, 0x02)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return

        step_describle = "安全访问"
        progress_value = 30
        security_level = 0x61
        r = uds27Service_response(self.udsHandle, security_level)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return

        # 下载flashDriver 开始---------------------
        # 34服务请求下载 
        step_describle = "34服务请求下载"
        progress_value = 35
        r = tsdiag_can_request_download(self.udsHandle, driver_start_address, driver_data_length)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return

        # 36服务传输数据
        # start_address = (c_uint8*4)(start_address)
        step_describle = "36服务传输数据"
        progress_value = 40
        driver_data = (c_uint8*driver_data_length)(*driver_data)
        r = tsdiag_can_transfer_data(self.udsHandle, driver_data, len(driver_data), 1)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return


        step_describle = "37服务退出传输"
        progress_value = 45
        r = tsdiag_can_request_transfer_exit(self.udsHandle)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return
        # 下载flashDriver 完成---------------------

        step_describle = "检查driver编程完整性"
        progress_value = 50
        request_data = (c_uint8*8)(0x31, 0x01, 0x02, 0x02, 0xE5, 0x1F, 0x72, 0x6F)
        r = uds31Service_response(self.udsHandle, request_data, type_checkDriverProgramIntegrity)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return

        # 擦除内存
        step_describle = "擦除内存"
        progress_value = 55
        request_data = (c_uint8*13)(0x31, 0x01, 0xFF, 0x00, 0x44, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x03, 0x00, 0x00)
        r = uds31Service_response(self.udsHandle, request_data, type_eraseMemory)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return


        # 下载app 开始---------------------
        step_describle = "34服务请求下载"
        progress_value = 60
        r = tsdiag_can_request_download(self.udsHandle, app_start_address, app_data_length)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return

        step_describle = "36服务传输数据"
        progress_value = 65
        app_data = (c_uint8*app_data_length)(*app_data)
        r = tsdiag_can_transfer_data(self.udsHandle, app_data, len(app_data), 1)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return

        step_describle = "37服务退出传输"
        progress_value = 70
        r = tsdiag_can_request_transfer_exit(self.udsHandle)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return
        # 下载app 完成---------------------


        step_describle = "检查app编程完整性"
        progress_value = 75
        request_data = (c_uint8*8)(0x31, 0x01, 0x02, 0x02, 0x9A, 0x1A, 0xBA, 0x15)
        r = uds31Service_response(self.udsHandle, request_data, type_checkAppProgramIntegrity)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return


        step_describle = "31 01 FF 01检测编程依赖"
        progress_value = 80
        request_data = (c_uint8*4)(0x31, 0x01, 0xFF, 0x01)
        r = uds31Service_response(self.udsHandle, request_data, type_checkProgramDependency)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return

        step_describle = "11 01复位"
        progress_value = 85
        r = ECU_Reset(self.udsHandle, reset_time = 3)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return

        step_describle = "10 03进扩展会话"
        progress_value = 90
        r = tsdiag_can_session_control(self.udsHandle, 0x03)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return

    
        step_describle = "28 00 03使能NM和APP报文收发"
        progress_value = 95
        r = enableNMAndAppMessage(self.udsHandle)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return


        step_describle = "85 81 00开启DTC记录"
        progress_value = 98
        r = openDTCRecord(self.udsHandle)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return


        step_describle = "10 01进默认会话"
        progress_value = 100
        r = tsdiag_can_session_control(self.udsHandle, 0x01)
        if self.handleFlashResult(r, step_describle, progress_value) == 1:
            return



    def handleFlashResult(self, r, step_describle, progress_value):
        if r!= 0:
            result = json.dumps({'result_type' : 'msgBox', 'msg' : step_describle + "失败"})
            self.ui_signal_showUiResult.emit(result)
            return 1
        else:
            result = json.dumps({'result_type' : 'flash_progress', 'progress_value' : progress_value})
            self.ui_signal_showUiResult.emit(result)
            # logger.info(step_describle + "成功")
            return 0